package lvm

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"github.com/sirupsen/logrus"
	"os/exec"
	"strconv"
	"strings"
	"time"
)

func DetectEnv() (err error) {
	cmds := []string{
		"lvs",
		"pvs",
		"vgs",
	}
	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancel()
	for _, cmd := range cmds {
		_, err = execCommand(ctx, cmd, "-h")
		if err != nil {
			logrus.Warnf("required command %s not found", cmd)
			return
		}
	}
	return
}

func execCommand(ctx context.Context, name string, arg ...string) (result string, err error) {
	cmd := exec.CommandContext(ctx, name, arg...)
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	logrus.Debugf("%+v", cmd.Args)
	err = cmd.Run()
	if err != nil {
		logrus.Warnf("cmd.Run() failed with %v, %v\n", err, stderr.String())
		return
	}
	result, errStr := stdout.String(), stderr.String()
	if len(errStr) != 0 {
		errStr = strings.TrimSpace(errStr)
		if !strings.HasPrefix(errStr, "WARNING") {
			logrus.Warn(errStr)
			err = errors.New(errStr)
			return
		}
	}
	return
}

// format: 9500098560B
func parseSize(str string) int64 {
	if s, err := strconv.Atoi(strings.Replace(str, "B", "", 1)); err == nil {
		return int64(s)
	}
	return 0
}

func isPVJoinable(ctx context.Context, pvName string) (err error) {
	pvs, err := PVList(ctx)
	if err != nil {
		return
	}
	pv, ok := pvs[pvName]
	if !ok {
		err = ErrNotFound
		return
	}
	if len(pv.VGName) > 0 {
		err = ErrPVAlreadyInUse
		return
	}
	return
}

func getVG(ctx context.Context, vgName string) *VolumeGroup {
	vgs, err := VGList(ctx)
	if err != nil {
		return nil
	}
	if vg, ok := vgs[vgName]; ok {
		return vg
	}
	return nil
}

func getLV(ctx context.Context, vgName, lvName string) *LogicalVolume {
	lvs, err := LVList(ctx)
	if err != nil {
		return nil
	}
	if lv, ok := lvs[fmt.Sprintf("%s/%s", vgName, lvName)]; ok {
		return lv
	}
	return nil
}
